package service

import (
	"context"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"time"

	"coupons/config"
	"coupons/repo"
	"coupons/repo/model"
	"coupons/router/middleware"

	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis/v8"
)

// SeckillService 秒杀服务
type SeckillService struct {
	voucherRepo *repo.VoucherRepo
	orderRepo   *repo.OrderRepo
	rdb         *redis.Client
	wsHub       *Hub
	config      *config.Config
}

// NewSeckillService 创建秒杀服务
func NewSeckillService(voucherRepo *repo.VoucherRepo, orderRepo *repo.OrderRepo, rdb *redis.Client, wsHub *Hub) *SeckillService {
	cfg := config.GetConfig()
	return &SeckillService{
		voucherRepo: voucherRepo,
		orderRepo:   orderRepo,
		rdb:         rdb,
		wsHub:       wsHub,
		config:      cfg,
	}
}

// Seckill 秒杀接口
func (s *SeckillService) Seckill(c *gin.Context) {
	var req model.SeckillRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(400, gin.H{
			"success": false,
			"message": "参数错误: " + err.Error(),
		})
		return
	}

	// 从JWT token获取用户Id
	userId, exists := middleware.GetUserId(c)
	if !exists {
		c.JSON(401, gin.H{
			"success": false,
			"message": "用户未登录",
		})
		return
	}

	// 执行秒杀
	result, err := s.executeSeckill(c.Request.Context(), req.VoucherId, userId)
	if err != nil {
		c.JSON(400, gin.H{
			"success": false,
			"message": err.Error(),
		})
		return
	}

	c.JSON(200, gin.H{
		"success": true,
		"data":    result,
	})
}

// executeSeckill 执行秒杀逻辑
func (s *SeckillService) executeSeckill(ctx context.Context, voucherId string, userId string) (*model.SeckillResult, error) {
	// 获取Lua脚本内容
	script, err := s.getLuaScript()
	if err != nil {
		return nil, fmt.Errorf("加载Lua脚本失败: %v", err)
	}

	// 构建Redis键
	stockKey := fmt.Sprintf("seckill:stock:%s", voucherId)
	orderKey := fmt.Sprintf("seckill:orders:%s", voucherId)
	lockKey := fmt.Sprintf("seckill:lock:%s:%s", voucherId, userId)

	// 执行Lua脚本
	result, err := s.rdb.Eval(ctx, script, []string{
		stockKey,
		orderKey,
		lockKey,
	}, voucherId, userId).Result()

	if err != nil {
		return nil, fmt.Errorf("Redis执行失败: %v", err)
	}

	code, ok := result.(int64)
	if !ok {
		return nil, fmt.Errorf("Lua脚本返回类型错误")
	}

	// 根据返回码处理结果
	switch code {
	case 0: // 成功
		// 异步创建订单
		go func() {
			// 创建新的context，避免HTTP请求结束后context被取消
			bgCtx := context.Background()

			// 从Redis获取优惠券金额
			amountKey := fmt.Sprintf("seckill:amount:%s", voucherId)
			amountStr, err := s.rdb.Get(bgCtx, amountKey).Result()
			if err != nil {
				log.Printf("获取优惠券金额失败: %v, 优惠券Id: %s", err, voucherId)
				return
			}

			amount, err := strconv.ParseFloat(amountStr, 64)
			if err != nil {
				log.Printf("解析优惠券金额失败: %v, 优惠券Id: %s", err, voucherId)
				return
			}

			// 设置当前时间为支付时间
			now := time.Now()
			order := &model.VoucherOrder{
				UserId:    userId,
				VoucherId: voucherId,
				Amount:    amount,
				PayTime:   &now,
				Status:    model.OrderStatusUnused, // 抢券成功即为已支付未使用状态
			}

			if err := s.orderRepo.CreateOrder(order); err != nil {
				log.Printf("创建订单失败: %v, 用户Id: %s, 优惠券Id: %s", err, userId, voucherId)
			} else {
				log.Printf("订单创建成功: 用户Id: %s, 优惠券Id: %s, 金额: %.2f", userId, voucherId, amount)
			}
		}()

		return &model.SeckillResult{
			Success: true,
			OrderId: 0, // 异步创建，暂时返回0
			Message: "抢券成功！",
		}, nil

	case 1:
		return nil, fmt.Errorf("库存不足，请下次再来")
	case 2:
		return nil, fmt.Errorf("您已经购买过该优惠券，请勿重复购买")
	default:
		return nil, fmt.Errorf("系统繁忙，请稍后重试")
	}
}

// GetVouchers 获取优惠券列表
func (s *SeckillService) GetVouchers(c *gin.Context) {
	vouchers, _, err := s.voucherRepo.GetVoucherList(0, 100) // 默认获取前100个
	if err != nil {
		c.JSON(500, gin.H{
			"success": false,
			"message": "获取优惠券列表失败",
		})
		return
	}

	c.JSON(200, gin.H{
		"success": true,
		"data":    vouchers,
	})
}

// GetVoucherByVoucherId 获取优惠券详情
func (s *SeckillService) GetVoucherByVoucherId(c *gin.Context) {
	voucherId := c.Param("voucher_id")
	if voucherId == "" {
		c.JSON(400, gin.H{
			"success": false,
			"message": "无效的优惠券Id",
		})
		return
	}

	voucher, err := s.voucherRepo.GetVoucherByVoucherId(voucherId)
	if err != nil {
		c.JSON(404, gin.H{
			"success": false,
			"message": "优惠券不存在",
		})
		return
	}

	c.JSON(200, gin.H{
		"success": true,
		"data":    voucher,
	})
}

// GetVoucherStock 获取优惠券库存
func (s *SeckillService) GetVoucherStock(c *gin.Context) {
	voucherId := c.Param("voucher_id")
	if voucherId == "" {
		c.JSON(400, gin.H{
			"success": false,
			"message": "无效的优惠券Id",
		})
		return
	}

	stockKey := fmt.Sprintf("seckill:stock:%s", voucherId)
	stock, err := s.rdb.Get(c.Request.Context(), stockKey).Int64()
	if err == redis.Nil {
		// 如果Redis中没有，从数据库获取
		voucher, err := s.voucherRepo.GetVoucherByVoucherId(voucherId)
		if err != nil {
			c.JSON(500, gin.H{
				"success": false,
				"message": "获取库存失败",
			})
			return
		}
		stock = int64(voucher.Stock)
	} else if err != nil {
		c.JSON(500, gin.H{
			"success": false,
			"message": "获取库存失败",
		})
		return
	}

	c.JSON(200, gin.H{
		"success": true,
		"data": map[string]interface{}{
			"voucher_id": voucherId,
			"stock":      stock,
		},
	})
}

// GetUserOrders 获取用户未使用的订单列表
func (s *SeckillService) GetUserOrders(c *gin.Context) {
	userId, exists := middleware.GetUserId(c)
	if !exists {
		c.JSON(401, gin.H{
			"success": false,
			"message": "用户未登录",
		})
		return
	}

	orders, err := s.orderRepo.GetUnusedOrdersByUserId(userId)
	if err != nil {
		c.JSON(500, gin.H{
			"success": false,
			"message": "获取订单失败: " + err.Error(),
		})
		return
	}

	c.JSON(200, gin.H{
		"success": true,
		"data":    orders,
	})
}

// GetOrderByVoucherId 获取订单详情
func (s *SeckillService) GetOrderByVoucherId(c *gin.Context) {
	orderId, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		c.JSON(400, gin.H{
			"success": false,
			"message": "无效的订单Id",
		})
		return
	}

	userId, exists := middleware.GetUserId(c)
	if !exists {
		c.JSON(401, gin.H{
			"success": false,
			"message": "用户未登录",
		})
		return
	}

	order, err := s.orderRepo.GetOrderById(orderId)
	if err != nil || order.UserId != userId {
		c.JSON(404, gin.H{
			"success": false,
			"message": "订单不存在",
		})
		return
	}

	c.JSON(200, gin.H{
		"success": true,
		"data":    order,
	})
}

// StartVoucherScanTask 启动优惠券扫描任务
func (s *SeckillService) StartVoucherScanTask(ctx context.Context) {
	ticker := time.NewTicker(time.Duration(s.config.Seckill.ScanInterval) * time.Second)
	defer ticker.Stop()

	for {
		select {
		case <-ctx.Done():
			return
		case <-ticker.C:
			s.scanUpcomingVouchers(ctx)
		}
	}
}

// scanUpcomingVouchers 扫描即将开始的优惠券
func (s *SeckillService) scanUpcomingVouchers(ctx context.Context) {
	now := time.Now()
	// 查找即将在1小时内开始的优惠券
	vouchers, err := s.voucherRepo.GetUpcomingVouchers(now)
	if err != nil {
		log.Printf("扫描优惠券失败: %v", err)
		return
	}

	log.Printf("扫描到 %d 个即将开始的优惠券", len(vouchers))

	for _, voucher := range vouchers {
		// // 检查Redis中是否已经加载过
		// stockKey := fmt.Sprintf("seckill:stock:%s", voucher.VoucherId)
		// exists, _ := s.rdb.Exists(ctx, stockKey).Result()
		// if exists > 0 {
		// 	 continue // 已经加载过，跳过
		// }

		err = s.voucherRepo.MarkAsNotified(voucher.VoucherId)
		// 加载优惠券到Redis
		s.loadVoucherToRedis(ctx, &voucher)

		// 通过WebSocket推送通知
		notification := &VoucherNotification{
			Type:      "voucher_upcoming",
			VoucherId: voucher.VoucherId,
			Title:     voucher.Title,
			Amount:    voucher.Amount,
			Stock:     voucher.Stock,
			BeginTime: voucher.BeginTime.Format("2006-01-02 15:04:05"),
			EndTime:   voucher.EndTime.Format("2006-01-02 15:04:05"),
			Message:   fmt.Sprintf("优惠券 '%s' 即将在1小时内开始抢购！", voucher.Title),
			Data: map[string]interface{}{
				"countdown":   voucher.BeginTime.Sub(now).Seconds(),
				"notify_time": now.Format("2006-01-02 15:04:05"),
			},
		}

		// 广播通知
		BroadcastVoucher(s.wsHub, notification)
		log.Printf("推送优惠券通知: %s (Id: %d)", voucher.Title, voucher.VoucherId)
	}
}

// loadVoucherToRedis 将优惠券信息加载到Redis
func (s *SeckillService) loadVoucherToRedis(ctx context.Context, voucher *model.SeckillVoucher) {
	stockKey := fmt.Sprintf("seckill:stock:%s", voucher.VoucherId)
	beginTimeKey := fmt.Sprintf("seckill:begin:%s", voucher.VoucherId)
	endTimeKey := fmt.Sprintf("seckill:end:%s", voucher.VoucherId)
	amountKey := fmt.Sprintf("seckill:amount:%s", voucher.VoucherId)

	s.rdb.Set(ctx, stockKey, voucher.Stock, 0)
	s.rdb.Set(ctx, beginTimeKey, voucher.BeginTime.Unix(), 0)
	s.rdb.Set(ctx, endTimeKey, voucher.EndTime.Unix(), 0)
	s.rdb.Set(ctx, amountKey, voucher.Amount, 0)
}

// getLuaScript 获取Lua脚本内容
func (s *SeckillService) getLuaScript() (string, error) {
	// 从根目录加载seckill.lua文件
	wd, _ := os.Getwd()
	luaPath := filepath.Join(wd, "seckill.lua")

	content, err := ioutil.ReadFile(luaPath)
	if err != nil {
		return "", fmt.Errorf("读取Lua脚本文件失败: %v", err)
	}

	return string(content), nil
}

// UseVoucher 使用优惠券
func (s *SeckillService) UseVoucher(c *gin.Context) {
	userId, exists := middleware.GetUserId(c)
	if !exists {
		c.JSON(401, gin.H{
			"success": false,
			"message": "用户未登录",
		})
		return
	}
	voucherId := c.Param("voucher_id")
	if voucherId == "" {
		c.JSON(400, gin.H{
			"success": false,
			"message": "优惠券ID不能为空",
		})
		return
	}

	// 使用优惠券
	err := s.orderRepo.UseVoucherByVoucherId(userId, voucherId)
	if err != nil {
		c.JSON(500, gin.H{
			"success": false,
			"message": "使用优惠券失败: " + err.Error(),
		})
		return
	}

	c.JSON(200, gin.H{
		"success": true,
		"message": "优惠券使用成功",
	})
}
